package net.sudot.commons.json;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import net.sudot.chess.exception.BusinessException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.util.List;
import java.util.Map;

/**
 * Jackson解析XML常用API工具
 *
 * @author tangjialin on 2018-08-13.
 */
public final class XmlUtils {
    private static final XmlMapper XML_MAPPER = new XmlMapper();

    public static XmlMapper getXmlMapper() {
        return XML_MAPPER;
    }

    /**
     * 不可实例化
     */
    private XmlUtils() {
    }

    /**
     * 将对象转换为XML字符串
     *
     * @param value 对象
     * @return XML字符串
     */
    public static String toXml(Object value) {
        if (value == null) { return null; }

        try {
            return XML_MAPPER.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将对象转换为XML流
     *
     * @param writer Writer
     * @param value  对象
     */
    public static void toXml(Writer writer, Object value) {
        try {
            XML_MAPPER.writeValue(writer, value);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将对象转换为XML流
     *
     * @param stream OutputStream
     * @param value  对象
     */
    public static void toXml(OutputStream stream, Object value) {
        try {
            XML_MAPPER.writeValue(stream, value);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将对象转换为XML字符串
     *
     * @param value 对象
     * @return XML字符串
     */
    public static byte[] toXmlBytes(Object value) {
        if (value == null) { return null; }

        try {
            return XML_MAPPER.writeValueAsBytes(value);
        } catch (JsonProcessingException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将对象转换为XML字符串并美化
     *
     * @param value 对象
     * @return XML字符串
     */
    public static String toPrettyXml(Object value) {
        if (value == null) { return null; }

        try {
            return XML_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(value);
        } catch (JsonProcessingException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为JSON对象
     *
     * @param xml XML字符串
     * @return 对象
     */
    public static JsonNode toObject(String xml) {
        try {
            return XML_MAPPER.readTree(xml);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为对象
     *
     * @param xml       XML字符串
     * @param valueType 类型
     * @return 对象
     */
    public static <T> T toObject(String xml, Class<T> valueType) {
        try {
            return XML_MAPPER.readValue(xml, valueType);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为对象
     * <pre>
     *     List<MyDto> asList = JsonUtils.toObject(xml, new TypeReference<List<MyDto>>() { });
     *     Map<String, Object> asMap = JsonUtils.toObject(xml, new TypeReference<Map<String, Object>>() { });
     * </pre>
     *
     * @param xml          XML字符串
     * @param valueTypeRef 类型
     * @return 对象
     */
    public static <T> T toObject(String xml, TypeReference<T> valueTypeRef) {
        try {
            return XML_MAPPER.readValue(xml, valueTypeRef);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为JSON对象
     *
     * @param xmlBytes XML字节数组
     * @return 对象
     */
    public static JsonNode toObject(byte[] xmlBytes) {
        try {
            return XML_MAPPER.readTree(xmlBytes);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为对象
     *
     * @param xmlBytes  XML字节数组
     * @param valueType 类型
     * @return 对象
     */
    public static <T> T toObject(byte[] xmlBytes, Class<T> valueType) {
        try {
            return XML_MAPPER.readValue(xmlBytes, valueType);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为对象
     * <pre>
     *     List<MyDto> asList = JsonUtils.toObject(xmlBytes, new TypeReference<List<MyDto>>() { });
     *     Map<String, Object> asMap = JsonUtils.toObject(xmlBytes, new TypeReference<Map<String, Object>>() { });
     * </pre>
     *
     * @param xmlBytes     JSON字节数组
     * @param valueTypeRef 类型
     * @return 对象
     */
    public static <T> T toObject(byte[] xmlBytes, TypeReference<T> valueTypeRef) {
        try {
            return XML_MAPPER.readValue(xmlBytes, valueTypeRef);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为JSON对象
     *
     * @param inputStream XML字符串输入流
     * @return 对象
     */
    public static JsonNode toObject(InputStream inputStream) {
        try {
            return XML_MAPPER.readTree(inputStream);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为对象
     *
     * @param inputStream XML字符串输入流
     * @param valueType   类型
     * @return 对象
     */
    public static <T> T toObject(InputStream inputStream, Class<T> valueType) {
        try {
            return XML_MAPPER.readValue(inputStream, valueType);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将XML字符串转换为对象
     * <pre>
     *     List<MyDto> asList = JsonUtils.toObject(xmlBytes, new TypeReference<List<MyDto>>() { });
     *     Map<String, Object> asMap = JsonUtils.toObject(xmlBytes, new TypeReference<Map<String, Object>>() { });
     * </pre>
     *
     * @param inputStream  XML字符串输入流
     * @param valueTypeRef 类型
     * @return 对象
     */
    public static <T> T toObject(InputStream inputStream, TypeReference<T> valueTypeRef) {
        try {
            return XML_MAPPER.readValue(inputStream, valueTypeRef);
        } catch (IOException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    /**
     * 将Object对象转换为Json对象
     *
     * @param value Object对象
     * @return 对象
     */
    public static <T extends JsonNode> T toObject(Object value) {
        if (value == null) { return null; }
        return XML_MAPPER.valueToTree(value);
    }

    /**
     * 将Object对象转换为指定类型对象
     *
     * @param value     Object对象
     * @param valueType 类型
     * @return 对象
     */
    public static <T> T toObject(Object value, Class<T> valueType) {
        if (value == null) { return null; }
        return XML_MAPPER.convertValue(value, valueType);
    }

    /**
     * 将Object对象转换为指定类型对象
     * <pre>
     *     List<MyDto> asList = JsonUtils.toObject(value, new TypeReference<List<MyDto>>() { });
     *     Map<String, Object> asMap = JsonUtils.toObject(value, new TypeReference<Map<String, Object>>() { });
     * </pre>
     *
     * @param value        Object对象
     * @param valueTypeRef 类型
     * @return 对象
     */
    public static <T> T toObject(Object value, TypeReference<T> valueTypeRef) {
        return XML_MAPPER.convertValue(value, valueTypeRef);
    }

    /**
     * 创建一个ObjectNode
     *
     * @return 返回ObjectNode
     */
    public static ObjectNode createObjectNode() {
        return XML_MAPPER.createObjectNode();
    }

    /**
     * 创建一个ObjectNode
     *
     * @param kids 用于存放json数据的map
     * @return 返回ObjectNode
     */
    public static ObjectNode createObjectNode(Map<String, JsonNode> kids) {
        return new ObjectNode(XML_MAPPER.getNodeFactory(), kids);
    }

    /**
     * 创建一个ArrayNode
     *
     * @return 返回ArrayNode
     */
    public static ArrayNode createArrayNode() {
        return XML_MAPPER.createArrayNode();
    }

    /**
     * 创建一个ArrayNode
     *
     * @param children 用于存放json数据的list
     * @return 返回ArrayNode
     */
    public static ArrayNode createArrayNode(List<JsonNode> children) {
        return new ArrayNode(XML_MAPPER.getNodeFactory(), children);
    }
}